#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <pthread.h>
#define NUM_CUSTOMERS 30
#define ROOM_CAPACITY 10


sem_t cust_room,barber;
pthread_key_t   tIsKey;


static sigset_t   signal_mask;


#define NUM_THREADS     50
pthread_t threads[NUM_THREADS];
#define ROOMCAPACITY     10


//Semaphores...
sem_t BarberChairSem;
sem_t RoomSem;



int waiting_chair_seats = 0;
int customersInRoom = 0;

int customerCount = 20;




void *barber_thread(void *arg)
{
       long tid;
       tid = (long)arg;

       sleep(2);

       printf("------------------------------------------\n[Barber]: opens the shop\n------------------------------------------\n");
       kill(getpid(),SIGINT);
      // raise(SIGINT);


       while(customerCount>0)
       {
           kill(getpid(),SIGINT);
           sem_post(&RoomSem);
           sem_post(&BarberChairSem);
           sleep(1);
           printf("[Barber]: Customers Remaining = [%d]\n",customerCount);
           printf("[Barber]: customer_in_room = %d\n",customersInRoom);
           printf("[barber] : Anyone wants hair cut?\n");


       }

       printf("[Barber]: No one? okay i will close this shop\n------------------------------------------\n");


}


void *customer_thread(void *arg)
 {

    long tid;
       tid = (long)arg;
        int       sig_caught;    /* signal caught       */
        int       rc;            /* returned code       */
        pthread_t     me = pthread_self();

        void *id;
        id = malloc(sizeof(tid));
        memcpy(id, &tid, sizeof(tid));

     
        pthread_setspecific(tIsKey, tid);


       printf("[customer - %ld] : Standing outside Barber Shop.\n", tid);
       rc = sigwait (&signal_mask, &sig_caught);
           if (rc != 0) {
               printf("Error waiting for Signal\n");
           }

           printf("[customer - %ld] : Door opened for me Barber Shop.\n", tid);

       sem_wait(&RoomSem);
       customersInRoom++;
       printf("[customer - %ld] : waiting for barber chair.\n", tid);

       sem_wait(&BarberChairSem);


       printf("[customer - %ld] : I am getting hair cut.\n", tid);

       customerCount --;
       customersInRoom--;
       printf("[Customer - %ld ] Leaves Barber shop.\n------------------------------------------\n",tid);

 }


void handler()
{


      printf("Attempting to print the id= %d\n", (int *) pthread_getspecific(tIsKey));

      



}	


int main()
{
          pthread_key_create(&tIsKey, NULL );


        int i,rc;
        long t=0; void *status;
        struct sigaction new_action;

        pthread_attr_t attr;
        /* Initialize and set thread detached attribute */
       pthread_attr_init(&attr);
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

       sem_init(&BarberChairSem, 0, 0);
       sem_init(&RoomSem,0,ROOMCAPACITY-1);


       new_action.sa_sigaction =handler;
       sigaction (SIGINT, &new_action, NULL);


       //sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);

       /*
        *       int sem_init(sem_t *sem, int pshared, unsigned int value);
        *
        *      sem points to a semaphore object to initialize
        *
        *         pshared is a flag indicating whether or not the semaphore should be shared with fork()ed processes.
        *         LinuxThreads does not currently support shared semaphores
        *
        *         value is an initial value to set the semaphore to
        *
        */


       for(i=1;i<=20;i++)
       {
         t=i;
          rc = pthread_create(&threads[i], &attr, customer_thread, (void *)t);
          if (rc){
             printf("ERROR; return code from pthread_create() is %d\n", rc);
             exit(-1);
          }
       }

        sigemptyset (&signal_mask);
        sigaddset (&signal_mask, SIGINT);
        rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
            if (rc != 0) {
               printf("Error masking signals for baarber!\n");
            }


       rc = pthread_create(&threads[0], &attr, barber_thread, (void *)t);
                 if (rc){
                    printf("ERROR; return code from pthread_create() is %d\n", rc);
                    exit(-1);
                 }


          rc = pthread_join(threads[0], &status);
              if (rc) {
                 printf("ERROR; return code from pthread_join() is %d\n", rc);
                 exit(-1);
             }

}


/*
 *
 *
 int pthread_sigmask (int how, const sigset_t *restrict set, sigset_t *restrict oset);
 int sigprocmask (int how, const sigset_t *restrict set, sigset_t *restrict oset);



 *
 */


